home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fs / fsStreamOps.c < prev    next >
C/C++ Source or Header  |  1991-07-23  |  31KB  |  1,017 lines

  1. /*
  2.  * fsStreamOps.c --
  3.  *
  4.  *    The has procedures for the following stream operations:
  5.  *    Read, Write, IOControl, Close.  Select and attributes functions
  6.  *    are in their own files.
  7.  *
  8.  * Copyright 1987 Regents of the University of California
  9.  * All rights reserved.
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /sprite/src/kernel/fs/RCS/fsStreamOps.c,v 9.24 91/07/23 14:56:22 shirriff Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23.  
  24. #include <sprite.h>
  25. #include <fs.h>
  26. #include <fsutil.h>
  27. #include <fsio.h>
  28. #include <fsNameOps.h>
  29. #include <fscache.h>
  30. #include <fsutilTrace.h>
  31. #include <fsStat.h>
  32. #include <fsdm.h>
  33. #include <fsprefix.h>
  34. #include <rpc.h>
  35. #include <vm.h>
  36. #include <fsrmt.h>
  37. #include <fslcl.h>
  38. #include <assert.h>
  39. #include <machparam.h>
  40. #include <string.h>
  41. #include <fspdev.h>
  42.  
  43. #ifdef SOSP91
  44. #include <sospRecord.h>
  45. #endif SOSP91
  46.  
  47. extern Boolean fsconsist_ClientCachingEnabled;
  48.  
  49.  
  50. /*
  51.  *----------------------------------------------------------------------
  52.  *
  53.  * Fs_Read --
  54.  *
  55.  *    Read from a stream.  The main jobs of this routine are to
  56.  *    set things up for (remote) waiting, and to branch out to
  57.  *    the procedure that implements Read for the type of the stream.
  58.  *    If the server is down, or the stream's handle has gone stale,
  59.  *    this blocks the process while waiting for handle recovery.
  60.  *    Also, the stream access position is maintained by this procedure,
  61.  *    even though the read offset is an explicit argument.
  62.  *
  63.  * Results:
  64.  *    A return status, SUCCESS if successful.
  65.  *
  66.  * Side effects:
  67.  *    The buffer is filled with the number of bytes indicated by
  68.  *    the length parameter.  The in/out length parameter specifies
  69.  *    the buffer size on input and is updated to reflect the number
  70.  *    of bytes actually read.
  71.  *
  72.  *----------------------------------------------------------------------
  73.  */
  74. ReturnStatus
  75. Fs_Read(streamPtr, buffer, offset, lenPtr)
  76.     Fs_Stream     *streamPtr;    /* Stream to read from. */
  77.     Address     buffer;        /* Where to read into. */
  78.     int     offset;        /* Where to start reading from. */
  79.     int     *lenPtr;    /* Contains number of bytes to read on input,
  80.                    and is filled with number of bytes read. */
  81. {
  82.     register ReturnStatus     status = SUCCESS;
  83.     Sync_RemoteWaiter        remoteWaiter;
  84.     Fs_IOParam            io;
  85.     register Fs_IOParam     *ioPtr = &io;
  86.     Fs_IOReply            reply;
  87.     int                streamType;
  88.     register int        toRead;
  89. #ifdef SOSP91
  90.     Boolean            isForeign = FALSE;
  91.  
  92.     if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  93.     if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  94.         (proc_RunningProcesses[0]->genFlags &
  95.         (PROC_FOREIGN | PROC_MIGRATING))) {
  96.         isForeign = TRUE;
  97.     }
  98.     }
  99. #endif SOSP91
  100.  
  101.     toRead = *lenPtr;
  102.     *lenPtr = 0;
  103.     if (sys_ShuttingDown) {
  104.     return(FAILURE);
  105.     } else if ((streamPtr->flags & FS_READ) == 0) {
  106.     return(FS_NO_ACCESS);
  107.     } else if (toRead == 0) {
  108.     return(SUCCESS);
  109.     } else if ((toRead < 0) || (offset < 0)) {
  110.     return(GEN_INVALID_ARG);
  111.     } else if (!Fsutil_HandleValid(streamPtr->ioHandlePtr)) {
  112.     return(FS_STALE_HANDLE);
  113.     }
  114.     streamType = streamPtr->ioHandlePtr->fileID.type;
  115.  
  116.     FsSetIOParam(ioPtr, buffer, toRead, offset, streamPtr->flags);
  117.     reply.length = 0;
  118.     reply.flags = 0;
  119.     reply.signal = 0;
  120.     reply.code = 0;
  121. #ifdef SOSP91
  122.     if (streamType == FSIO_LCL_FILE_STREAM) {
  123.     ioPtr->reserved = rpc_SpriteID;
  124.     }
  125. #endif SOSP91
  126.  
  127.     /*
  128.      * Outer loop to attempt the read and then block if no data is ready.
  129.      * The loop terminates upon error or if any data is transferred.
  130.      */
  131.     remoteWaiter.hostID = rpc_SpriteID;
  132.     while (TRUE) {
  133.     Sync_GetWaitToken(&remoteWaiter.pid, &remoteWaiter.waitToken);
  134.  
  135.     status = (fsio_StreamOpTable[streamType].read) (streamPtr,
  136.             ioPtr, &remoteWaiter, &reply);
  137. #ifdef lint
  138.     status = Fsio_FileRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  139.     status = FsrmtFileRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  140.     status = Fsio_DeviceRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  141.     status = Fsio_PipeRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  142.     status = FspdevControlRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  143.     status = FspdevServerStreamRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  144.     status = FspdevPseudoStreamRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  145.     status = Fsrmt_Read(streamPtr, ioPtr, &remoteWaiter, &reply);
  146. #endif
  147.  
  148. #ifdef SOSP91
  149.     if (streamType == FSIO_RMT_DEVICE_STREAM ||
  150.         streamType == FSIO_RMT_PIPE_STREAM ||
  151.         streamType == FSIO_RMT_PSEUDO_STREAM ||
  152.         streamType == FSIO_RMT_PFS_STREAM ||
  153.         streamType == FSIO_RMT_CONTROL_STREAM) {
  154.         fs_MoreStats.remoteDevicishBytesRead += reply.length;
  155.         if (isForeign) {
  156.         fs_MoreStats.remoteDevicishBytesReadM += reply.length;
  157.         }
  158.     }
  159. #endif SOSP91
  160.     if (status == SUCCESS) {
  161.         break;
  162.     } else if (status == FS_WOULD_BLOCK && 
  163.         (streamPtr->flags & FS_NON_BLOCKING) == 0) {
  164.         /*
  165.          * File streams will return FS_WOULD_BLOCK when waiting for a
  166.          * cache block, but stuff has already been returned.  We want
  167.          * to wait instead of returning.
  168.          */
  169.         if (reply.length > 0 && (streamType != FSIO_LCL_FILE_STREAM) &&
  170.         (streamType != FSIO_RMT_FILE_STREAM)) {
  171.         /*
  172.          * Stream routine ought not do return FS_WOULD_BLOCK
  173.          * in this case, but we cover for it here.
  174.          */
  175.         status = SUCCESS;
  176.         break;
  177.         } else if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  178.         status = GEN_ABORTED_BY_SIGNAL;
  179.         break;
  180.         }
  181.     } else if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  182.                status == RPC_SERVICE_DISABLED)  {
  183.         status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
  184.         if (status != SUCCESS) {
  185.         break;
  186.         }
  187.     } else {
  188.         if (status == FS_WOULD_BLOCK && reply.length > 0) {
  189.         /*
  190.          * Cannot return FS_WOULD_BLOCK if some data was read.
  191.          */
  192.         status = SUCCESS;
  193.         }
  194.         break;
  195.     }
  196.     /*
  197.      * Restore the length parameter because it may have been set to
  198.      * zero when the read blocked.
  199.      */
  200.     ioPtr->length = toRead;
  201.     }
  202.  
  203.  
  204. #ifdef SOSP91
  205.     /*
  206.      * Record the fact that we read from the stream.
  207.      */
  208.     streamPtr->hdr.flags |= FSUTIL_RW_READ;
  209. #endif
  210.  
  211.     /*
  212.      * Cache the file offset for sequential access.
  213.      */
  214.     streamPtr->offset += reply.length;
  215.     *lenPtr = reply.length;
  216.  
  217.     if (status == FS_BROKEN_PIPE) {
  218.     Sig_Send(SIG_PIPE, 0, PROC_MY_PID, FALSE, (Address)0);
  219.     } else if (reply.signal != 0) {
  220.     Sig_Send(reply.signal, reply.code, PROC_MY_PID, FALSE, (Address)0);
  221.     }
  222.     return(status);
  223. }
  224.  
  225.  
  226. /*
  227.  *----------------------------------------------------------------------
  228.  *
  229.  * Fs_Write --
  230.  *
  231.  *    Write to a stream.  This sets up for (remote) waiting and then
  232.  *    branches to the routine that implements writing for the stream.
  233.  *    If the server is down, or the streams handle has gone stale,
  234.  *    this will block the process while waiting for handle recovery.
  235.  *    Finally, the stream access position of the stream is maintained
  236.  *    even though the write offset is an explicit parameter.
  237.  *
  238.  * Results:
  239.  *    A return status, SUCCESS if successful.
  240.  *
  241.  * Side effects:
  242.  *    The data in the buffer is written to the file at the indicated offset.
  243.  *    The in/out length parameter specifies the amount of data to write
  244.  *    and is updated to reflect the number of bytes actually written.
  245.  *    The stream offset field is updated to after the bytes written.
  246.  *
  247.  *----------------------------------------------------------------------
  248.  */
  249. ReturnStatus
  250. Fs_Write(streamPtr, buffer, offset, lenPtr)
  251.     Fs_Stream *streamPtr;        /* The stream to write to */
  252.     Address buffer;            /* The buffer to fill in */
  253.     int offset;                /* Where in the stream to write to */
  254.     int *lenPtr;            /* In/Out byte count */
  255. {
  256.     register ReturnStatus     status = SUCCESS;    /* I/O return status */
  257.     Sync_RemoteWaiter    remoteWaiter;        /* Process info for waiting */
  258.     Fs_IOParam        io;            /* Write parameter block */
  259.     register Fs_IOParam *ioPtr = &io;
  260.     Fs_IOReply        reply;            /* Return length, signal */
  261.     int            toWrite;        /* Amount remaining to write.
  262.                          * Keep our own copy because
  263.                          * lower-levels may modify
  264.                          * ioPtr->length */
  265.     register int    amountWritten;        /* Amount transferred */
  266.     int            streamType;        /* Type from I/O handle */
  267.  
  268.     toWrite = *lenPtr;
  269.     amountWritten = 0;
  270.     *lenPtr = 0;
  271.     if (sys_ShuttingDown) {
  272.     return(FAILURE);
  273.     } else if ((streamPtr->flags & FS_WRITE) == 0) {
  274.     return(FS_NO_ACCESS);
  275.     } else if (toWrite == 0) {
  276.     return(SUCCESS);
  277.     } else if ((toWrite < 0) || (offset < 0)) {
  278.     return(GEN_INVALID_ARG);
  279.     } else if (!Fsutil_HandleValid(streamPtr->ioHandlePtr)) {
  280.     return(FS_STALE_HANDLE);
  281.     }
  282.     streamType = streamPtr->ioHandlePtr->fileID.type;
  283.  
  284.     FsSetIOParam(ioPtr, buffer, toWrite, offset, streamPtr->flags);
  285.     reply.length = 0;
  286.     reply.flags = 0;
  287.     reply.signal = 0;
  288.     reply.code = 0;
  289.  
  290.     remoteWaiter.hostID = rpc_SpriteID;
  291.  
  292.     FSUTIL_TRACE_IO(FSUTIL_TRACE_WRITE, streamPtr->ioHandlePtr->fileID, offset,toWrite);
  293.     /*
  294.      * Main write loop.  This handles partial writes, non-blocking streams,
  295.      * and crash recovery.  This loop expects the stream write procedure to
  296.      * return FS_WOULD_BLOCK if it transfers no data, and lets it return
  297.      * either SUCCESS or FS_WOULD_BLOCK on partial writes.  SUCCESS with a
  298.      * partial write makes this loop return.
  299.      * If a stream write procedure returns FS_WOULD_BLOCK is is required to
  300.      * have put the remoteWaiter information on an appropriate wait list.
  301.      * This loop ensures that a non-blocking stream returns SUCCESS if some
  302.      * data is transferred, and FS_WOULD_BLOCK if none can be transferred now.
  303.      */
  304.     while (TRUE) {
  305.     Sync_GetWaitToken(&remoteWaiter.pid, &remoteWaiter.waitToken);
  306.  
  307.     status = (fsio_StreamOpTable[streamType].write) (streamPtr, ioPtr,
  308.                               &remoteWaiter, &reply);
  309. #ifdef lint
  310.     status = Fsio_FileWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  311.     status = FsrmtFileWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  312.     status = Fsio_DeviceWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  313.     status = Fsio_PipeWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  314.     status = FspdevPseudoStreamWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  315.     status = Fsrmt_Write(streamPtr, ioPtr, &remoteWaiter, &reply);
  316. #endif
  317.     toWrite -= reply.length;
  318.     amountWritten += reply.length;
  319.     /*
  320.      * Reset pointers because stream-specific routine may have
  321.      * modified them arbitrarily.
  322.      */
  323.     ioPtr->buffer = buffer + amountWritten;
  324.     ioPtr->offset = offset + amountWritten;
  325.     ioPtr->length = toWrite;
  326.     if (status == SUCCESS) {
  327.         break;
  328.     } else if (status == FS_WOULD_BLOCK) {
  329.         if ((streamPtr->flags & FS_NON_BLOCKING) == 0) {
  330.         if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  331.             status = GEN_ABORTED_BY_SIGNAL;
  332.             break;
  333.         }
  334.         } else {
  335.         if (amountWritten > 0) {
  336.             status = SUCCESS;    /* non-blocking partial write */
  337.         }
  338.         break;
  339.         }
  340.     } else if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  341.                status == RPC_SERVICE_DISABLED)  {
  342.         status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
  343.         if (status != SUCCESS) {
  344.         break;
  345.         }
  346.     } else {
  347.         break;            /* stream error */
  348.     }
  349.     }
  350. #ifdef SOSP91
  351.     /*
  352.      * Record the fact that we read from the stream.
  353.      */
  354.     streamPtr->hdr.flags |= FSUTIL_RW_WRITE;
  355. #endif
  356.     /*
  357.      * Return info about the transfer.
  358.      */
  359.     *lenPtr = amountWritten;
  360.     streamPtr->offset += amountWritten;
  361.     if (status == FS_BROKEN_PIPE) {
  362.     Sig_Send(SIG_PIPE, 0, PROC_MY_PID, FALSE, (Address)0);
  363.     } else if (reply.signal != 0) {
  364.     Sig_Send(reply.signal, reply.code, PROC_MY_PID, FALSE, (Address)0);
  365.     }
  366.  
  367.     return(status);
  368. }
  369.  
  370. /*
  371.  *----------------------------------------------------------------------
  372.  *
  373.  * Fs_IOControl --
  374.  *
  375.  *    Generic IOControl handler.  This will also propogate ALL
  376.  *    IOControls down to lower levels, mainly so that pseudo-device
  377.  *    drivers (user-level server programs) will see all of them.
  378.  *
  379.  * Results:
  380.  *    An error code that depends in the command
  381.  *
  382.  * Side effects:
  383.  *    Command specific
  384.  *
  385.  *----------------------------------------------------------------------
  386.  */
  387.  
  388. ReturnStatus
  389. Fs_IOControl(streamPtr, ioctlPtr, replyPtr)
  390.     register Fs_Stream *streamPtr;
  391.     Fs_IOCParam *ioctlPtr;        /* I/O Control parameter block */
  392.     Fs_IOReply *replyPtr;        /* Return length and signal */
  393. {
  394.     register ReturnStatus    status;
  395.     register Boolean        retry;
  396.     register int        command = ioctlPtr->command;
  397.     int                offset;
  398.     Ioc_LockArgs        *lockArgsPtr;
  399.     register int        streamType;
  400.  
  401.     lockArgsPtr = (Ioc_LockArgs *) NIL;
  402.     /*
  403.      * Retry loop to handle server error recovery and blocking locks.
  404.      */
  405.     streamType = streamPtr->ioHandlePtr->fileID.type;
  406.     do {
  407.     if (!Fsutil_HandleValid((Fs_HandleHeader *)streamPtr) ||
  408.         !Fsutil_HandleValid((Fs_HandleHeader *)streamPtr->ioHandlePtr)) {
  409.         return(FS_STALE_HANDLE);
  410.     }
  411.     retry = FALSE;
  412.     replyPtr->length = ioctlPtr->outBufSize;
  413.     replyPtr->flags = 0;
  414.     replyPtr->signal = 0;
  415.     replyPtr->code = 0;
  416.     /*
  417.      * Pre-processing for some of the IOControls.
  418.      *
  419.      * IOC_NUM_READABLE.  We pass the stream offset
  420.      * down using the inBuffer so that the stream-type-specific routines
  421.      * can correctly compute how much data is available.  (Still have to
  422.      * do this even though we pass the streamPtr down because the offset
  423.      * on the server may not be up-to-date.  Probably fixable.)
  424.      *
  425.      * IOC_LOCK and IOC_UNLOCK.  We have to fill in the process and hostID
  426.      * entries in the buffer passed in from the user.
  427.      *
  428.      * IOC_PREFIX.  This is processed here and not passed down to
  429.      * lower levels.  This looks at the streamPtr->nameInfoPtr which
  430.      * is completely generic and not otherwise needed by lower levels.
  431.      * This simplifies the object modules and eliminates an RPC in the
  432.      * case that the object is remote.
  433.      */
  434.     if (command == IOC_NUM_READABLE) {
  435.         offset = streamPtr->offset;
  436.         ioctlPtr->inBuffer = (Address) &offset;
  437.         ioctlPtr->inBufSize = sizeof(int);
  438.         ioctlPtr->flags &= ~FS_USER_IN;
  439.     } else if (command == IOC_LOCK || command == IOC_UNLOCK) {
  440.         lockArgsPtr = (Ioc_LockArgs *)ioctlPtr->inBuffer;
  441.         lockArgsPtr->hostID = rpc_SpriteID;
  442.         Sync_GetWaitToken(&lockArgsPtr->pid, &lockArgsPtr->token);
  443.     } else if (command == IOC_PREFIX) {
  444.         Fsprefix    *prefixPtr;
  445.         if ((streamPtr->nameInfoPtr == (Fs_NameInfo *) NIL) ||
  446.         (streamPtr->nameInfoPtr->prefixPtr == (Fsprefix *)NIL)) {
  447.         status = GEN_INVALID_ARG;
  448.         } else {
  449.         prefixPtr = streamPtr->nameInfoPtr->prefixPtr;
  450.         if (ioctlPtr->outBufSize < prefixPtr->prefixLength) {
  451.             status = GEN_INVALID_ARG;
  452.         } else {
  453.             strcpy(ioctlPtr->outBuffer, prefixPtr->prefix);
  454.             replyPtr->length = prefixPtr->prefixLength + 1;
  455.             status = SUCCESS;
  456.         }
  457.         }
  458.         return(status);    /* Do not pass down IOC_PREFIX */
  459. #ifdef SOSP91
  460.     } else if ((command == IOC_REPOSITION) &&
  461.         (streamType == FSIO_RMT_FILE_STREAM)) {
  462.         int        *ptr;
  463.         Fs_Attributes attrs;
  464.         Ioc_RepositionArgs *iocArgsPtr;
  465.         iocArgsPtr = (Ioc_RepositionArgs *) ioctlPtr->inBuffer;
  466.  
  467.         ptr = (int *) (ioctlPtr->inBuffer + 
  468.                     sizeof(Ioc_RepositionArgs));
  469.         *ptr++ = streamPtr->offset;
  470.         if (iocArgsPtr->base == IOC_BASE_EOF) {
  471.         status = Fs_GetAttrStream(streamPtr, &attrs);
  472.         if (status == SUCCESS) {
  473.             *ptr++ = attrs.size;
  474.         } else {
  475.             *ptr++ = -1;
  476.         }
  477.         } else {
  478.         *ptr++ = -1;
  479.         }
  480.         *ptr++ = ((streamPtr->hdr.flags & FSUTIL_RW_FLAGS) >> 8);
  481.         streamPtr->hdr.flags &= ~FSUTIL_RW_FLAGS;
  482.         ioctlPtr->inBufSize += sizeof(int) * 3;
  483. #endif
  484.     }
  485.  
  486.     status = (*fsio_StreamOpTable[streamType].ioControl)
  487.             (streamPtr, ioctlPtr, replyPtr);
  488. #ifdef lint
  489.     status = Fsio_FileIOControl(streamPtr, ioctlPtr, replyPtr);
  490.     status = FsrmtFileIOControl(streamPtr, ioctlPtr, replyPtr);
  491.     status = Fsio_DeviceIOControl(streamPtr, ioctlPtr, replyPtr);
  492.     status = Fsrmt_IOControl(streamPtr, ioctlPtr, replyPtr);
  493.     status = Fsio_PipeIOControl(streamPtr, ioctlPtr, replyPtr);
  494.     status = FspdevControlIOControl(streamPtr, ioctlPtr, replyPtr);
  495.     status = FspdevServerStreamIOControl(streamPtr, ioctlPtr, replyPtr);
  496.     status = FspdevPseudoStreamIOControl(streamPtr, ioctlPtr, replyPtr);
  497. #endif /* lint */
  498.  
  499.     switch(status) {
  500.         case SUCCESS:
  501.         break;
  502.         case RPC_TIMEOUT:
  503.         case RPC_SERVICE_DISABLED:
  504.         case FS_STALE_HANDLE:
  505.         status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
  506.         if (status == SUCCESS) {
  507.             retry = TRUE;
  508.             break;
  509.         } else {
  510.             return(status);
  511.         }
  512.         case FS_WOULD_BLOCK:
  513.         /*
  514.          * Blocking I/O control.  Should be a lock, although some
  515.          * pseudo-device servers (like ipServer) will return
  516.          * this status code for their own reasons.
  517.          */
  518.         if ((command == IOC_LOCK) &&
  519.             ((lockArgsPtr->flags & IOC_LOCK_NO_BLOCK) == 0)) {
  520.             if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  521.             return(GEN_ABORTED_BY_SIGNAL);
  522.             } else {
  523.             retry = TRUE;
  524.             break;
  525.             }
  526.         } else {
  527.             return(status);
  528.         }
  529.         default:
  530.         return(status);
  531.     }
  532.     } while (retry);
  533.  
  534.     /*
  535.      * Do generic I/O controls that affect streams -
  536.      * flag manipulation, and offset seeking.
  537.      */
  538.     switch (command) {
  539.     case IOC_REPOSITION: {
  540.         /*
  541.          * Set the read/write offset of the stream.
  542.          */
  543.         register int newOffset;
  544.         register Ioc_RepositionArgs    *iocArgsPtr;
  545.  
  546.         if (ioctlPtr->inBuffer == (Address)NIL) {
  547.         status = GEN_INVALID_ARG;
  548.         break;
  549.         }
  550.         iocArgsPtr = (Ioc_RepositionArgs *)ioctlPtr->inBuffer;
  551.         newOffset = -1;
  552.         switch(iocArgsPtr->base) {
  553.         case IOC_BASE_ZERO:
  554.             newOffset = iocArgsPtr->offset;
  555.             break;
  556.         case IOC_BASE_CURRENT:
  557.             newOffset = streamPtr->offset + iocArgsPtr->offset;
  558.             break;
  559.         case IOC_BASE_EOF: {
  560.             Fs_Attributes attrs;
  561.  
  562.             status = Fs_GetAttrStream(streamPtr, &attrs);
  563.             if (status != SUCCESS) {
  564.             break;
  565.             }
  566.             newOffset = attrs.size + iocArgsPtr->offset;
  567.             break;
  568.         }
  569.         }
  570.         if (newOffset < 0) {
  571.         status = GEN_INVALID_ARG;
  572.         } else {
  573.         if (ioctlPtr->outBuffer != (Address)NIL) {
  574.             *(int *)ioctlPtr->outBuffer = newOffset;
  575.             replyPtr->length = sizeof(int);
  576.         }
  577. #ifdef SOSP91
  578.         if ((streamType == FSIO_LCL_FILE_STREAM) && 
  579.             (newOffset != streamPtr->offset)) {
  580.             SOSP_ADD_LSEEK_TRACE(streamPtr->hdr.fileID, 
  581.             streamPtr->offset, newOffset, 
  582.             ((streamPtr->hdr.flags & FSUTIL_RW_FLAGS) >> 8));
  583.             streamPtr->hdr.flags &= ~FSUTIL_RW_FLAGS;
  584.         }
  585. #endif
  586.         streamPtr->offset = newOffset;
  587.         }
  588.         break;
  589.     }
  590.     /*
  591.      * Stream flags manipulation.  There are the FS_ constants which
  592.      * have a place in the streams flag field, and the IOC_ constants
  593.      * which user programs know about.  These allow flexibility, but
  594.      * requires specific checking for each kernel flag...
  595.      */
  596.     case IOC_GET_FLAGS: {
  597.         /*
  598.          * OR the kernel flags from the stream into the output flags word.
  599.          */
  600.         register int flags = 0;
  601.         if (streamPtr->flags & FS_APPEND) {
  602.         flags |= IOC_APPEND;
  603.         }
  604.         if (streamPtr->flags & FS_NON_BLOCKING) {
  605.         flags |= IOC_NON_BLOCKING;
  606.         }
  607.         if (ioctlPtr->outBufSize != sizeof(int)) {
  608.         status = GEN_INVALID_ARG;
  609.         } else {
  610.         *(int *)ioctlPtr->outBuffer |= flags;
  611.         replyPtr->length = sizeof(int);
  612.         }
  613.         break;
  614.     }
  615.     case IOC_SET_BITS:
  616.     case IOC_SET_FLAGS: {
  617.         /*
  618.          * Set any kernel stream flags specifid by the IOControl flags.
  619.          * We rely on the file-type IOControl routine to verify
  620.          * the validity of the flag choices.  See that IOC_SET_FLAGS
  621.          * differs from IOC_SET_BITS by turning off any bits that
  622.          * are not in the input word.
  623.          */
  624.         register int flags;
  625.         if (ioctlPtr->inBufSize != sizeof(int)) {
  626.         status = GEN_INVALID_ARG;
  627.         break;
  628.         }
  629.         flags = *(int *)ioctlPtr->inBuffer;
  630.         if ((flags & IOC_APPEND) && (streamPtr->flags & FS_WRITE) == 0) {
  631.         status = FS_NO_ACCESS;
  632.         break;
  633.         }
  634.         if (flags & IOC_APPEND) {
  635.         streamPtr->flags |= FS_APPEND;
  636.         } else if (command == IOC_SET_FLAGS) {
  637.         streamPtr->flags &= ~FS_APPEND;
  638.         }
  639.         if (flags & IOC_NON_BLOCKING) {
  640.         streamPtr->flags |= FS_NON_BLOCKING;
  641.         } else if (command == IOC_SET_FLAGS) {
  642.         streamPtr->flags &= ~FS_NON_BLOCKING;
  643.         }
  644.         break;
  645.     }
  646.     case IOC_CLEAR_BITS:{
  647.         register int flags;
  648.         if (ioctlPtr->inBufSize != sizeof(int)) {
  649.         status = GEN_INVALID_ARG;
  650.         break;
  651.         }
  652.         flags = *(int *)ioctlPtr->inBuffer;
  653.         if (flags & IOC_APPEND) {
  654.         streamPtr->flags &= ~FS_APPEND;
  655.         }
  656.         if (flags & IOC_NON_BLOCKING) {
  657.         streamPtr->flags &= ~FS_NON_BLOCKING;
  658.         }
  659.         break;
  660.     }
  661.     /*
  662.      * Everything for the following has already been handled by
  663.      * the stream specific IOControl routines.
  664.      */
  665.     case IOC_LOCK:
  666.     case IOC_UNLOCK:
  667.     case IOC_NUM_READABLE:
  668.     case IOC_TRUNCATE:
  669.     case IOC_GET_OWNER:
  670.     case IOC_SET_OWNER:
  671.     case IOC_MAP:
  672.          break;
  673.     }
  674.     /*
  675.      * Generate signal returned from stream-specific routine.
  676.      */
  677.     if (replyPtr->signal != 0) {
  678.     Sig_Send(replyPtr->signal, replyPtr->code, PROC_MY_PID, FALSE,
  679.         (Address)0);
  680.     }
  681.     return(status);
  682. }
  683.  
  684. /*
  685.  *----------------------------------------------------------------------
  686.  *
  687.  * Fs_Close --
  688.  *
  689.  *    Free this reference to the Stream.  The reference count is decreased
  690.  *    and when it goes to zero the stream close routine is called
  691.  *    to release the reference to the I/O handle.
  692.  *
  693.  * Results:
  694.  *    None.
  695.  *
  696.  * Side effects:
  697.  *      If the ref count is zero after the decrement,  the reference to
  698.  *      the file is released and the input parameter is free'd.
  699.  *
  700.  *----------------------------------------------------------------------
  701.  */
  702.  
  703. ReturnStatus
  704. Fs_Close(streamPtr)
  705.     register Fs_Stream     *streamPtr;
  706. {
  707.     register ReturnStatus     status;
  708.     Proc_ControlBlock        *procPtr;
  709.  
  710.     if (streamPtr == (Fs_Stream *)NIL) {
  711.     /*
  712.      * Bomb-proofing.  The current directory sometimes doesn't get
  713.      * found at boot time and so there is a NIL streamPtr around for it.
  714.      */
  715.     return(FS_INVALID_ARG);
  716.     }
  717.     Fsutil_HandleLock(streamPtr);
  718.     procPtr = Proc_GetEffectiveProc();
  719.     if (streamPtr->hdr.refCount > 1) {
  720.     /*
  721.      * There are other copies of the stream (due to fork/dup) so
  722.      * we don't close the I/O handle yet.
  723.      */
  724.     Fsutil_HandleRelease(streamPtr, TRUE);
  725.     status = SUCCESS;
  726.     } else {
  727.     /*
  728.      * Call the stream type close routine to clean up this reference
  729.      * to the I/O handle.
  730.      */
  731.     Fsutil_HandleLock(streamPtr->ioHandlePtr);
  732.  
  733. #ifdef SOSP91
  734.     status = (fsio_StreamOpTable[streamPtr->ioHandlePtr->fileID.type].close)
  735.         (streamPtr, rpc_SpriteID, procPtr->processID, streamPtr->flags,
  736.         0, (ClientData)NIL, (int *) NIL, (int *) NIL);
  737. #else 
  738.     status = (fsio_StreamOpTable[streamPtr->ioHandlePtr->fileID.type].close)
  739.         (streamPtr, rpc_SpriteID, procPtr->processID, streamPtr->flags,
  740.         0, (ClientData)NIL);
  741. #endif
  742. #ifdef lint
  743.     status = Fsio_FileClose(streamPtr, rpc_SpriteID, procPtr->processID,
  744.         streamPtr->flags, 0, (ClientData)NIL);
  745.     status = FsrmtFileClose(streamPtr, rpc_SpriteID, procPtr->processID,
  746.         streamPtr->flags, 0, (ClientData)NIL);
  747.     status = Fsio_PipeClose(streamPtr, rpc_SpriteID, procPtr->processID,
  748.         streamPtr->flags, 0, (ClientData)NIL);
  749.     status = Fsio_DeviceClose(streamPtr, rpc_SpriteID, procPtr->processID,
  750.         streamPtr->flags, 0, (ClientData)NIL);
  751.     status = Fsrmt_IOClose(streamPtr, rpc_SpriteID, procPtr->processID,
  752.         streamPtr->flags, 0, (ClientData)NIL);
  753.     status = FspdevControlClose(streamPtr, rpc_SpriteID, procPtr->processID,
  754.         streamPtr->flags, 0, (ClientData)NIL);
  755.     status = FspdevPseudoStreamClose(streamPtr, rpc_SpriteID,procPtr->processID,
  756.         streamPtr->flags, 0, (ClientData)NIL);
  757.     status = FspdevServerStreamClose(streamPtr, rpc_SpriteID,procPtr->processID,
  758.         streamPtr->flags, 0, (ClientData)NIL);
  759. #endif /* lint */
  760.     if (Fsio_StreamClientClose(&streamPtr->clientList, rpc_SpriteID)) {
  761.         Fsio_StreamDestroy(streamPtr);
  762.     } else {
  763.         Fsutil_HandleRelease(streamPtr, TRUE);
  764.     }
  765.     }
  766.     return(status);
  767. }
  768.  
  769.  
  770. /*
  771.  *----------------------------------------------------------------------
  772.  *
  773.  * Fs_CheckSetID --
  774.  *
  775.  *    Determine if the given stream has the set uid or set gid bits set.
  776.  *
  777.  * Results:
  778.  *    None.
  779.  *
  780.  * Side effects:
  781.  *    *uidPtr and *gidPtr set to -1 if the respective bit isn't set and set
  782.  *    to the uid and/or gid of the file otherwise.
  783.  *
  784.  *----------------------------------------------------------------------
  785.  */
  786. void
  787. Fs_CheckSetID(streamPtr, uidPtr, gidPtr)
  788.     Fs_Stream    *streamPtr;
  789.     int        *uidPtr;
  790.     int        *gidPtr;
  791. {
  792.     register    Fscache_Attributes    *cachedAttrPtr;
  793.  
  794.     switch (streamPtr->ioHandlePtr->fileID.type) {
  795.     case FSIO_LCL_FILE_STREAM:
  796.         cachedAttrPtr =
  797.            &((Fsio_FileIOHandle *)streamPtr->ioHandlePtr)->cacheInfo.attr;
  798.         break;
  799.     case FSIO_RMT_FILE_STREAM:
  800.         cachedAttrPtr =
  801.            &((Fsrmt_FileIOHandle *)streamPtr->ioHandlePtr)->cacheInfo.attr;
  802.         break;
  803.     case FSIO_LCL_PFS_STREAM:
  804.     case FSIO_RMT_PFS_STREAM:
  805.         /* Could do get attributes request to the PFS here
  806.          * but in general it could be a security hole so  
  807.          * we won't allow setuid or setgid programs in a PFS. JMS.
  808.          */
  809.         cachedAttrPtr = (Fscache_Attributes *)NIL;
  810.         break;
  811.     default:
  812.         panic( "Fs_CheckSetID, wrong stream type\n",
  813.         streamPtr->ioHandlePtr->fileID.type);
  814.         return;
  815.     }
  816.     if ((cachedAttrPtr != (Fscache_Attributes *)NIL) &&
  817.     (cachedAttrPtr->permissions & FS_SET_UID)) {
  818.     *uidPtr = cachedAttrPtr->uid;
  819.     } else {
  820.     *uidPtr = -1;
  821.     }
  822.     if ((cachedAttrPtr != (Fscache_Attributes *)NIL) &&
  823.     (cachedAttrPtr->permissions & FS_SET_GID)) {
  824.     *gidPtr = cachedAttrPtr->gid;
  825.     } else {
  826.     *gidPtr = -1;
  827.     }
  828. }
  829.  
  830. /*
  831.  *----------------------------------------------------------------------
  832.  *
  833.  * Fs_FileWriteBackStub --
  834.  *
  835.  *      This is the stub for the Fs_WriteBackID system call.
  836.  *    The byte arguments are rounded to blocks, and the range of
  837.  *    blocks that covers the byte range is written back out of the cache.
  838.  *
  839.  * Results:
  840.  *    A return status or SUCCESS if successful.
  841.  *
  842.  * Side effects:
  843.  *    Write out the range of blocks in the cache.
  844.  *
  845.  *----------------------------------------------------------------------
  846.  */
  847. ReturnStatus
  848. Fs_FileWriteBackStub(streamID, firstByte, lastByte, shouldBlock)
  849.     int        streamID;    /* Stream ID of file to write back. */
  850.     int        firstByte;    /* First byte to write back. */
  851.     int        lastByte;    /* Last byte to write back. */
  852.     Boolean    shouldBlock;    /* TRUE if should wait for the blocks to go
  853.                  * to disk. */
  854. {
  855.     Ioc_WriteBackArgs args;
  856.  
  857.     args.firstByte = firstByte;
  858.     args.lastByte = lastByte;
  859.     args.shouldBlock = shouldBlock;
  860.  
  861.     return( Fs_IOControlStub(streamID, IOC_WRITE_BACK, sizeof(args),
  862.                     (Address)&args, 0, (Address)0) );
  863. }
  864.  
  865. /*
  866.  *----------------------------------------------------------------------
  867.  *
  868.  * Fs_FileBeingMapped --
  869.  *
  870.  *      This is called by VM when a file is being mapped into
  871.  *    a user's virtual address (yuck, blech), or is being
  872.  *    unmapped from the address space.  This does a
  873.  *    write-back/invalidate so that the file is not cached
  874.  *    by FS any longer.  This ensures that paging traffic
  875.  *    wont get stale data.
  876.  *
  877.  * Results:
  878.  *    A return status or SUCCESS if successful.
  879.  *
  880.  * Side effects:
  881.  *    Write out the range of blocks in the cache.
  882.  *
  883.  *----------------------------------------------------------------------
  884.  */
  885. ReturnStatus
  886. Fs_FileBeingMapped(streamPtr, isMapped)
  887.     Fs_Stream *streamPtr;    /* Open stream being mapped in */
  888.     int        isMapped;    /* 1 if file is being mapped. */
  889. {
  890.     ReturnStatus status = SUCCESS;
  891.     Fscache_FileInfo    *cacheInfoPtr;
  892.     Fs_IOCParam    ioctl;
  893.     Fs_IOReply    reply;
  894.  
  895.     if (isMapped) {
  896.     /*
  897.      * THIS IS BOGUS.  The whole thing should be done via I/O control
  898.      * so this routine isn't polluted with checks against the stream type.
  899.      */
  900.     switch(streamPtr->ioHandlePtr->fileID.type) {
  901.         case FSIO_LCL_FILE_STREAM: {
  902.         register Fsio_FileIOHandle *localHandlePtr;
  903.         localHandlePtr = (Fsio_FileIOHandle *)streamPtr->ioHandlePtr;
  904.         cacheInfoPtr = &localHandlePtr->cacheInfo;
  905.         break;
  906.         }
  907.         case FSIO_RMT_FILE_STREAM: {
  908.         register Fsrmt_FileIOHandle *rmtHandlePtr;
  909.         rmtHandlePtr = (Fsrmt_FileIOHandle *)streamPtr->ioHandlePtr;
  910.         cacheInfoPtr = &rmtHandlePtr->cacheInfo;
  911.         break;
  912.         }
  913.         default:
  914.         return(FS_WRONG_TYPE);
  915.     }
  916.     /*
  917.      * Make the file look like a swap file so the local cache
  918.      * is bypassed.  Also flush back any modified data so
  919.      * page-ins get good stuff.
  920.      */
  921.     streamPtr->flags |= FS_SWAP;
  922.     }
  923.     /*
  924.      * Tell the file server what's going on.
  925.      */
  926.     if (status == SUCCESS) {
  927.     Proc_ControlBlock    *procPtr = Proc_GetEffectiveProc();
  928.     ioctl.command = IOC_MAP;
  929.     ioctl.inBuffer = (Address)&isMapped;
  930.     ioctl.inBufSize = sizeof(int);
  931.     ioctl.outBuffer = (Address) NIL;
  932.     ioctl.outBufSize = 0;
  933.     ioctl.format = mach_Format;
  934.     ioctl.procID = procPtr->processID;
  935.     ioctl.familyID = procPtr->familyID;
  936.     ioctl.uid = procPtr->effectiveUserID;
  937.     ioctl.flags = 0;
  938.     status = Fs_IOControl(streamPtr, &ioctl, &reply);
  939.     }
  940.     return(status);
  941. }
  942.  
  943. /*
  944.  *----------------------------------------------------------------------------
  945.  *
  946.  * Fs_GetFileHandle --
  947.  *
  948.  *    Return an opaque handle for a file, really a pointer to its I/O handle.
  949.  *    This is used for a subsequent call to Fs_GetSegPtr.
  950.  *
  951.  * Results:
  952.  *    A pointer to the I/O handle of the file.
  953.  *
  954.  * Side effects:
  955.  *    None.
  956.  *
  957.  *----------------------------------------------------------------------------
  958.  *
  959.  */
  960.  
  961. ClientData
  962. Fs_GetFileHandle(streamPtr)
  963.     Fs_Stream *streamPtr;
  964. {
  965.     return((ClientData)streamPtr->ioHandlePtr);
  966. }
  967.  
  968. /*
  969.  *----------------------------------------------------------------------------
  970.  *
  971.  * Fs_GetSegPtr --
  972.  *
  973.  *    Return a pointer to a pointer to the segment associated with this
  974.  *    file.
  975.  *
  976.  * Results:
  977.  *    A pointer to the segment associated with this file.
  978.  *
  979.  * Side effects:
  980.  *    None.
  981.  *
  982.  *----------------------------------------------------------------------------
  983.  *
  984.  */
  985.  
  986. Vm_Segment **
  987. Fs_GetSegPtr(fileHandle)
  988.     ClientData fileHandle;
  989. {
  990.     Fs_HandleHeader *hdrPtr = (Fs_HandleHeader *)fileHandle;
  991.     Vm_Segment    **segPtrPtr;
  992.  
  993.     assert(((unsigned int) fileHandle & WORD_ALIGN_MASK) == 0);
  994.     switch (hdrPtr->fileID.type) {
  995.     case FSIO_LCL_FILE_STREAM:
  996.         segPtrPtr = &(((Fsio_FileIOHandle *)hdrPtr)->segPtr);
  997.         break;
  998.     case FSIO_RMT_FILE_STREAM:
  999.         segPtrPtr = &(((Fsrmt_FileIOHandle *)hdrPtr)->segPtr);
  1000.         break;
  1001.     case FSIO_LCL_PFS_STREAM:
  1002.     case FSIO_RMT_PFS_STREAM:
  1003.         segPtrPtr = &(((Fspdev_ClientIOHandle *)hdrPtr)->segPtr);
  1004.         break;
  1005.     default:
  1006.         segPtrPtr = (Vm_Segment **) NIL;
  1007.         panic( "Fs_RetSegPtr, bad stream type %d\n",
  1008.             hdrPtr->fileID.type);
  1009.     }
  1010.     fs_Stats.handle.segmentFetches++;
  1011.     if (*segPtrPtr != (Vm_Segment *) NIL) {
  1012.     fs_Stats.handle.segmentHits++;
  1013.     }
  1014.     return(segPtrPtr);
  1015. }
  1016.  
  1017.